#include <DFI.h>

DFI::DFI(Ice::ObjectAdapterPtr oa)
{
  IceStorm::TopicManagerPrx topicManager;

  // Reference to the topic manager.
  try {
    Ice::ObjectPrx base = oa->getCommunicator()->stringToProxy("FIPA.IceStorm/TopicManager");
    topicManager = IceStorm::TopicManagerPrx::checkedCast(base);
  }
  catch (Ice::Exception& ex)
    {
      cout << "Invalid topic manager: " << ex << endl;
      throw Ice::Exception();
    }

  // DF channel.
  try
    {
      _df = topicManager->retrieve("DF");
      cout << "Topic DF retrieved." << endl;
    }
  catch (IceStorm::NoSuchTopic&)
    {
      _df = topicManager->create("DF");
      cout << "Topic DF created." << endl;
      }
}
 
DFI::~DFI()
{
}

// Register a new agent description with the DF.
void
DFI::_cpp_register
(const FIPA::DfAgentDescription& desc, 
 const Ice::Current&)
{
  IceUtil::Mutex::Lock lock(_m);

  if (_agents.find(desc.name->ice_getIdentity()) == _agents.end())
    _agents[desc.name->ice_getIdentity()] = desc;
  else
    throw FIPA::AgentExists();

  // Advise the other subscribers.
  this->notify(FIPA::Registration, desc);
}

void 
DFI::deregister
(const Ice::Identity& id, 
 const Ice::Current&)
{
  IceUtil::Mutex::Lock lock(_m);

  // Advise the other subscribers.
  if (_agents.find(id) != _agents.end())
    {
      this->notify(FIPA::Deregistration, _agents[id]);
      _agents.erase(id);
    }
}
  
void
DFI::modify
(const FIPA::DfAgentDescription& desc, 
 const Ice::Current&)
{
  IceUtil::Mutex::Lock lock(_m);

  // Advise the other subscribers.
  if (_agents.find(desc.name->ice_getIdentity()) != _agents.end())
    {
      _agents[desc.name->ice_getIdentity()] = desc;
      this->notify(FIPA::Modification, _agents[desc.name->ice_getIdentity()]);
    }
}

FIPA::AgentSeq
DFI::search
(const FIPA::DfAgentDescription& desc,  
 const Ice::Current&)
{
  IceUtil::Mutex::Lock lock(_m);

  FIPA::AgentSeq agents;
  RMap::const_iterator ita;
  vector<FIPA::ServiceDescription>::const_iterator its;
  
  for (ita = _agents.begin();
       ita != _agents.end();
       ++ita)
    for (its = ita->second.services.begin();
	 its != ita->second.services.end();
	 ++its)
      if (its->name == desc.services[0].name)
	agents.push_back(ita->second.name);

  return agents;
}

void
DFI::subscribe
(const FIPA::AgentPrx& aid,
 const Ice::Current&)
{
  try {
    IceStorm::QoS qos;
    _df->subscribeAndGetPublisher(qos, aid);
  }
  catch (IceStorm::AlreadySubscribed&) {
    throw FIPA::AlreadySubscribed();
  }
}

void
DFI::unsubscribe
(const FIPA::AgentPrx& aid,
 const Ice::Current&)
{
  _df->unsubscribe(aid);
}

void
DFI::adv
(const ::Ice::ObjectPrx&, 
 const ::Ice::Current&)
{
}

void
DFI::bye
(const ::Ice::Identity&, 
 const ::Ice::Current&)
{
}

void
DFI::lookup
(const ::Ice::ObjectPrx&, 
 const ::std::string&, 
 const ::PropertyService::Properties&, 
 const ::Ice::Current&)
{
}

void
DFI::discover
(const ::Ice::Current&)
{
}

void
DFI::notify
(const FIPA::DFAction& act,
 const FIPA::DfAgentDescription& desc)
{
  Ice::ObjectPrx pub = _df->getPublisher()->ice_oneway();
  FIPA::AgentPrx agent = FIPA::AgentPrx::uncheckedCast(pub);
  agent->dfAdv(act, desc);
}
